package cn.tang.tframe.common.utils;

import cn.tang.tframe.common.utils.lang.StringUtils;
import cn.tang.tframe.common.utils.reflect.ReflectionWrap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 打印对象方法
 *
 * @author tanghc
 * @since 2015/11/6.
 */
public class ToStringUtil {
	static Logger logger = LoggerFactory.getLogger(ToStringUtil.class);
	static ReflectionWrap reflectionWrap = new ReflectionWrap();

	/**
	 * 连接多个字符串
	 */
	public static String join(Object... objs) {
		return joinWith("", objs);
	}

	/**
	 * 连接多个字符串
	 */
	public static String joinWith(String split, Object... objs) {
		StringBuffer sbuf = new StringBuffer();
		if (null != objs) {
			int i = 0;
			for (Object o : objs) {
				if (i++ != 0) {
					sbuf.append(split);
				}
				sbuf.append(tripToEmptyString(o));
			}
		}
		return sbuf.toString();
	}

	/**
	 * 生成tostring字符串。格式为
	 * Bean[field1=value1,field2=value2,filed3=Field3Bean[field3BeanFeild1=value1]]
	 * 属性值如果是jdk中的类型，直接调用tostring方法，如果是自定义的类型，递归调用该方法。
	 *
	 * @param bean
	 * @return
	 */
	public static String reflectionToString(Object bean) {
		return reflectionToString(bean, 100, 1024);
	}
	public static String reflectionToString(Object bean,int argLength,int totalMaxLength) {
		if (null == bean) {
			return null;
		}
		StringBuffer sbuf = new StringBuffer();
		try {
			Class<?> beanClass = bean.getClass();
			if (hasOverrideToString(beanClass)) {
				return bean.toString();
			}
			sbuf.append(beanClass.getSimpleName());
			sbuf.append("{");
			if (Collection.class.isAssignableFrom(beanClass)) {
				sbuf.append(join((Collection) bean, ","));
			} else if (Map.class.isAssignableFrom(beanClass)) {
				sbuf.append(joinMap((Map) bean, ","));
			} else if (beanClass.isArray()) {
				sbuf.append(joinArray(bean, ","));
			} else if (beanClass.isEnum() || isJavaClass(beanClass)) {
				return bean.toString();
			} else {
				Map<String, Field> fields = reflectionWrap.getFields(beanClass);
				if (null != fields) {
					int i = 0;
					for (Map.Entry<String, Field> entry : fields.entrySet()) {
						String key = entry.getKey();
						Field field = entry.getValue();
						if (null != field) {
							ToStringIgnor tostringIgnor = field.getAnnotation(ToStringIgnor.class);
							if (null != tostringIgnor) {
								continue;
							}
							field.setAccessible(true);
							Object fieldValue = reflectionWrap.invokeField(field, bean);
							if (i++ != 0) {
								sbuf.append(" ,");
							}
							sbuf.append(key);
							sbuf.append("=");
							String s = reflectionToString(fieldValue, argLength,totalMaxLength);
							if(StringUtils.isNotBlank(s) && s.length() > argLength){
								s = s.substring(0,argLength)+"...";
							}
							sbuf.append(s);
						}
					}
				}
			}
			sbuf.append("}");
		} catch (Exception e) {
			logger.error("buildToString error: bean={}", new Object[] { bean, e });
		}
		String s = sbuf.toString();
		if(StringUtils.isNotBlank(s) && s.length() > totalMaxLength){
			s = s.substring(0,totalMaxLength)+"...";
		}
		return s;
	}

	private static boolean isJavaClass(Class clz) {
		return clz != null && clz.getClassLoader() == null;
	}

	public static String join(Collection collection, String separator) {
		if (null == collection) {
			return null;
		}
		StringBuffer sbuf = new StringBuffer();
		if (null != collection) {
			try {
				int i = 0;
				Iterator iterator = collection.iterator();
				while (iterator.hasNext()) {
					if (i++ != 0) {
						sbuf.append(separator);
					}
					Object next = iterator.next();
					sbuf.append(reflectionToString(next));
				}
			} catch (Exception e) {
				sbuf.append(collection);
			}
		}
		return sbuf.toString();
	}

	public static String joinMap(Map<Object, Object> map, String separator) {
		if (null == map) {
			return null;
		}
		StringBuffer sbuf = new StringBuffer();
		if (null != map) {
			try {
				int i = 0;
				for (Map.Entry<Object, Object> entry : map.entrySet()) {
					if (i++ != 0) {
						sbuf.append(separator);
					}
					sbuf.append(reflectionToString(entry.getKey()));
					sbuf.append("=");
					sbuf.append(reflectionToString(entry.getValue()));
				}
			} catch (Exception e) {
				sbuf.append(map);
			}
		}
		return sbuf.toString();
	}

	public static String joinArray(Object array, String separator) {
		if (null == array) {
			return null;
		}
		if (!array.getClass().isArray()) {
			return array.toString();
		}
		StringBuffer sbuf = new StringBuffer();
		try {
			int length = Array.getLength(array);
			for (int i = 0; i < length; i++) {
				if (i != 0) {
					sbuf.append(separator);
				}
				sbuf.append(reflectionToString(Array.get(array, i)));
			}
		} catch (Exception e) {
			sbuf.append(array);
		}
		return sbuf.toString();
	}

	public static void main(String[] args) {
		Map<String, Object> map = new HashMap<>();
		map.put("aaa", new Object());
		map.put("bbb", "3333");
		Object[] obs = new Object[] { new Object(), "aaaa", map };
		System.out.println(reflectionToString(obs));

		System.out.println(getChatCount("中文abc123！@#"));
		System.out.println(getChatCount2("中文abc123"));
	}

	public static boolean hasOverrideMethod(String method, Class clazz, Class<?>... parameterTypes) {
		if (null == clazz || null == method) {
			return false;
		}
		try {
			Method declaredMethod = clazz.getDeclaredMethod(method, parameterTypes);
			if (null != declaredMethod) {
				return true;
			}
		} catch (NoSuchMethodException e) {
			return false;
		}
		return false;
	}

	public static boolean hasOverrideToString(Class clazz) {
		return hasOverrideMethod("toString", clazz);
	}

	public static Object tripToEmpty(Object o) {
		if (null == o) {
			return "";
		}
		return o;
	}

	public static String tripToEmptyString(Object o) {
		if (null == o) {
			return "";
		}
		return o.toString();
	}

	/**
	 * 计算字符长度，中文算两个字符
	 * @param s
	 * @return
	 */
	public static   int getChatCount(String s)
	{
		if(null == s){
			return 0;
		}
		s = s.replaceAll("[^\\x00-\\xff]", "**");
		int length = s.length();
		return length;
	}
	public static int getChatCount2(String s)
	{
		if(null == s){
			return 0;
		}
		int length = 0;
		for(int i = 0; i < s.length(); i++)
		{
			int ascii = Character.codePointAt(s, i);
			if(ascii >= 0 && ascii <=255)
				length++;
			else
				length += 2;
		}
		return length;
	}

	public static String filterEmoji(String source,String replaceChar) {
		if (source != null) {
			Pattern emoji = Pattern.compile("[ud83cudc00-ud83cudfff]|[ud83dudc00-ud83dudfff]|[u2600-u27ff]", Pattern
					.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
			Matcher emojiMatcher = emoji.matcher(source);
			if (emojiMatcher.find()) {
				source = emojiMatcher.replaceAll(replaceChar);
				return source;
			}
			return source;
		}
		return source;
	}
}
